// File Buffer Class
// (c) jimon game studio

#include "CFileBuffer.h"
#include "ILogManager.h"

namespace je
{
	namespace core
	{
		//! Constructor
		CFileBuffer::CFileBuffer(const jeStringd & NewFileName,u1 IsRead,u1 IsWrite)
			:FileName(NewFileName),File(NULL),IsCanRead(IsRead),IsCanWrite(IsWrite),Locked(false),Ok(false)
		{
			if(IsCanRead)
				OpenFile();
		}

		//! Destructor
		CFileBuffer::~CFileBuffer()
		{
			if(File)
				fclose(File);
		}

		//! Lock Buffer
		void CFileBuffer::Lock(BufferLockType NewLockType)
		{
			JEASSERT(!Locked)
			Locked = true;
			LockType = NewLockType;
		}

		//! UnLock Buffer
		void CFileBuffer::UnLock()
		{
			JEASSERT(Locked)
			Locked = false;
		}

		//! Return True if locked
		u1 CFileBuffer::IsLocked()
		{
			return Locked;
		}

		//! Read Data
		void CFileBuffer::Read(void * Pointer,u32 SizeInBytes)
		{
			JEASSERT(Locked)
			JEASSERT((LockType == BLT_READ) || (LockType == BLT_READWRITE))

			if(File && IsCanRead)
			{
				if(StreamWorkMode)
					#ifdef JE_MSVC
					fread_s(Pointer,SizeInBytes,sizeof(c8),SizeInBytes,File);
					#else
					fread(Pointer,sizeof(c8),SizeInBytes,File);
					#endif
				else
				{
					u32 Pos = GetPosition();
					#ifdef JE_MSVC
					fread_s(Pointer,SizeInBytes,sizeof(c8),SizeInBytes,File);
					#else
					fread(Pointer,sizeof(c8),SizeInBytes,File);
					#endif
					SetPosition(Pos);
				}
			}
		}

		//! Write Data
		void CFileBuffer::Write(const void * Pointer,u32 SizeInBytes)
		{
			JEASSERT(Locked)
			JEASSERT((LockType == BLT_WRITE) || (LockType == BLT_READWRITE))

			if(File && IsCanWrite)
			{
				if(StreamWorkMode)
					fwrite(Pointer,sizeof(c8),SizeInBytes,File);
				else
				{
					u32 Pos = GetPosition();
					fwrite(Pointer,sizeof(c8),SizeInBytes,File);
					SetPosition(Pos);
				}
			}
		}

		//! Allocate Buffer for data,size is count of objects
		void CFileBuffer::Allocate(u32 NewSize)
		{
			JEASSERT(Locked)
			JEASSERT((LockType == BLT_WRITE) || (LockType == BLT_READWRITE))
			OpenFile();
		}

		//! DeAllocate Buffer
		void CFileBuffer::DeAllocate()
		{
			JEASSERT(Locked)
			JEASSERT((LockType == BLT_WRITE) || (LockType == BLT_READWRITE))
			if(File)
				fclose(File);
			File = NULL;
		}

		//! Set Position
		void CFileBuffer::SetPosition(u32 NewPosition,u1 Relative)
		{
			if(File)
			{
				if(Relative)
					fseek(File,NewPosition,SEEK_CUR);
				else
					fseek(File,NewPosition,SEEK_SET);
			}
		}

		//! Get Position
		u32 CFileBuffer::GetPosition()
		{
			if(File)
				return ftell(File);
			else
				return 0;
		}

		//! Get Size in bytes
		u32 CFileBuffer::GetSize()
		{
			return FileSize;
		}

		//! Get Size of one object
		u32 CFileBuffer::GetObjectSize()
		{
			return 1;
		}

		//! Return File Name
		const jeStringd & CFileBuffer::GetFileName()
		{
			return FileName;
		}

		//! Return true if file opened,or writed correctlly
		u1 CFileBuffer::IsOk()
		{
			return Ok;
		}

		//! Open File
		void CFileBuffer::OpenFile()
		{
			jeStringd OpenMode;

			if(IsCanRead)
				if(IsCanWrite)
					OpenMode = "w+b";
				else
					OpenMode = "rb";
			else
				OpenMode = "wb";


			File = NULL;
			#ifdef JE_UNICODE
				#ifdef JE_MSVC
					if(_wfopen_s(&File,FileName.c_str(),OpenMode.c_str()))
				#else
					#ifdef JE_LINUX
						// i dont really like this trick
						File = fopen(jeStringc(FileName.c_str()).c_str(),jeStringc(OpenMode.c_str()).c_str());
					#else
						File = _wfopen(FileName.c_str(),OpenMode.c_str());
					#endif
					if(File == NULL)
				#endif
			#else
				#ifdef JE_MSVC
					if(fopen_s(&File,FileName.c_str(),OpenMode.c_str()))
				#else
					File = fopen(FileName.c_str(),OpenMode.c_str());
					if(File == NULL)
				#endif
			#endif
			{
				JELOG_E("Cant open file buffer")
				return;
			}

			if(File)
			{
				fseek(File, 0, SEEK_END);
				FileSize = GetPosition();
				fseek(File, 0, SEEK_SET);
			}

			Ok = true;
		}
	}
}
